<template>
  <div class="card p-4 leading-normal">
    <h3 class="text-xl">拖拽概念</h3>
    <p class="p-2 mt-2">
      拖拽事件，主要涉及两个元素，一个是被（我们）拖的元素 DragElement
      ，另一个是放（我们）拖的目标元素 DropElement
    </p>
    <h4 class="mt-2">DragElement 相关事件</h4>
    <ul class="p-2">
      <li>drag：拖拉过程中，在被拖拉的节点上持续触发（相隔几百毫秒）。</li>
      <li>
        dragstart：用户开始拖拉时，在被拖拉的节点上触发，该事件的target属性是被拖拉的节点。通常应该在这个事件的监听函数中，指定拖拉的数据。
      </li>
      <li>
        dragend：拖拉结束时（释放鼠标键或按下 ESC
        键）在被拖拉的节点上触发，该事件的target属性是被拖拉的节点。它与dragstart事件，在同一个节点上触发。不管拖拉是否跨窗口，或者中途被取消，dragend事件总是会触发的。
      </li>
    </ul>
    <h4 class="mt-2">DropElement 相关事件</h4>
    <ul class="p-2">
      <li>
        dragenter：拖拉进入当前节点时，在当前节点上触发一次，该事件的target属性是当前节点。通常应该在这个事件的监听函数中，指定是否允许在当前节点放下（drop）拖拉的数据。如果当前节点没有该事件的监听函数，或者监听函数不执行任何操作，就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点，也是在这个事件的监听函数中设置。
      </li>
      <li>
        dragover：拖拉到当前节点上方时，在当前节点上持续触发（相隔几百毫秒），该事件的target属性是当前节点。该事件与dragenter事件的区别是，dragenter事件在进入该节点时触发，然后只要没有离开这个节点，dragover事件会持续触发。
      </li>
      <li>
        dragleave：拖拉操作离开当前节点范围时，在当前节点上触发，该事件的target属性是当前节点。如果要在视觉上显示拖拉离开操作当前节点，就在这个事件的监听函数中设置。
      </li>
      <li>
        drop：被拖拉的节点或选中的文本，释放到目标节点时，在目标节点上触发。注意，如果当前节点不允许drop，即使在该节点上方松开鼠标键，也不会触发该事件。如果用户按下
        ESC 键，取消这个操作，也不会触发该事件。该事件的监听函数负责取出拖拉数据，并进行相关处理。
      </li>
    </ul>
    <p>
      注意，一旦某个元素节点的draggable属性设为true，就无法再用鼠标选中该节点内部的文字或子节点了。
    </p>
    <div class="flex gap-4 mt-4">
      <div ref="dragElement" class="flex-1 drag-element" draggable="true">
        <a href="https://baidu.com/">DragElement</a>
      </div>
      <div ref="dropElement" class="flex-1 drop-element">
        <input type="text" value="DropElement" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
const dragElement = ref()
const dropElement = ref()

const dragstart = function (e) {
  this.style.backgroundColor = 'red'
  this.style.color = 'white'
  e.dataTransfer.effectAllowed = 'move'
}

const dragend = function (e) {
  this.style.backgroundColor = ''
  this.style.color = ''
}

const dragover = function (e) {
  // html大部分元素默认是不允许放入的，这里禁止默认行为，那么就是可以放入的了
  e.preventDefault()
  e.dataTransfer.dropEffect = 'move'
}

const drop = function (e) {
  e.preventDefault()
  console.log('drop', e.dataTransfer)
}

onMounted(() => {
  dragElement.value.addEventListener('dragstart', dragstart, false)
  dragElement.value.addEventListener('dragend', dragend, false)
  dropElement.value.addEventListener('dragover', dragover, false)
  dropElement.value.addEventListener('drop', drop, false)
})

onUnmounted(() => {
  dragElement.value.removeEventListener('dragstart', dragstart, false)
  dragElement.value.removeEventListener('dragend', dragend, false)
  dropElement.value.removeEventListener('dragover', dragover, false)
  dropElement.value.removeEventListener('drop', drop, false)
})
</script>

<style scoped lang="scss">
.drag-element {
  height: 50px;
  border: 2px dashed red;
}
.drop-element {
  height: 50px;
  border: 2px dashed green;
}
</style>
